209. 长度最小的子数组
209. 长度最小的子数组
分析
注意,我们只需要分析长度最小子数组的长度,只需要返回这个长度数字即可:用一个数字来表示最小长度,然后有更小的就更新它,最后返回这个数字即可。
其实代码随想录里的题解说这是滑动窗口的方法,其实我觉得本质上还是双指针法,而且代码随想录里的写法太复杂了,不利于记忆,所以这里就采用我自己的写法。
如何找到符合要求的子数组呢?
从慢指针到快指针的子数组 [slow,fast]
为当前子数组
- 如果子数组的元素和小于指定值,就移动快指针,
- 如果子数组的元素和大于等于指定值,就移动慢指针,并更新子数组长度。
这种方式就是像毛毛虫走路一样,前进一截,然后从后面缩回来一截,再前进一截,再从后面缩回来一截,因为我们要找的是连续的几个元素组成的子数组,所以只要有符合要求的子数组,一定会被这种方式扫描到。
什么时候跳出循环呢?当子数字的元素和小于指定值,需要移动快指针的时候,而快指针已经到数组的最后一个元素的时候,就可以直接退出了。
用双指针法,总共就三步: - 什么时候移动快指针
- 什么时候移动慢指针
- 什么时候跳出循环
写算法题,我们首先要明确我们声明的每个变量的意义,根据我们对变量的定义,赋予初始值。然后根据我们对变量的定义来制定判断条件
解题
public int minSubArrayLen(int target, int[] nums) {
// 默认给一个值,第一次更新的时候,只要实际值小于这个值就行,可以用 Integer.MAX_VALUE ,不过用 nums.length+1 就够了
int maxLength = nums.length+1;
int subLength = maxLength;
// 因为快慢指针都从0开始,此时相当于以及指定了一个子数组,因此此时子数组的元素和就是nums[0]
int subSum = nums[0];
// 快慢指针都从0开始
int slow =0,fast =0;
for(;;){
if(subSum<target){
// 元素和小于指定值,移动快指针
fast++;
// 跳出循环的条件就是快指针到 nums.length
if(fast>nums.length-1){
break;
}
// 移动快指针之后,子数组元素和也要更新
subSum+=nums[fast];
}else{
// 元素和大于等于指定值,开始计算子数组长度
int nowLength = fast-slow+1;
if(nowLength<subLength){
// 比上一次计算的值小,才更新
subLength = nowLength;
}
// 移动慢指针
slow++;
// 移动慢指针之后,子数组元素和也要更新
subSum-=nums[slow];
}
}
// 没有找到满足要求的子数组,返回0
if(subLength==maxLength){
return 0;
}
// 返回 subLength
return subLength;
}
相关题
26. 删除有序数组中的重复项
27. 移除元素
283. 移动零
844. 比较含退格的字符串
977. 有序数组的平方
移动窗口
904. 水果成篮
76. 最小覆盖子串